package org.flyframework.command
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	
	[Event("change")]
	
	
	public class History extends EventDispatcher implements IHistory
	{
		
		[Bindable]
		public var maxSize:int = 10;
		
		[Bindable]
		public var undos:Array = new Array();
		[Bindable]
		public var redos:Array = new Array();
		
		
		//--------------------------------------------------------------------------
		// Init
		//--------------------------------------------------------------------------
		
		public function History( maxSize:int=10 )
		{
			this.maxSize = maxSize;
		}
		
		
		//--------------------------------------------------------------------------
		// Public
		//--------------------------------------------------------------------------
		
		public function execute( cmd:ICommand, event:Event=null ):void
		{
			cmd.execute( event );
			
			if( cmd.canUndo() )
			{
				this.undos.push( cmd );
				trim();
			}
			
			//this.redos.removeAll();
			this.redos = new Array();
			
			dispatchEvent( new Event("change") );
		}
		
		public function undo( event:Event=null ):void
		{
			if( this.undos.length == 0 ) return;
			
			var cmd:ICommand = this.undos.pop();
			if( cmd && cmd.canUndo() )
			{
				cmd.undo( event );
				
				if( cmd.canRedo() )
				{
					this.redos.push( cmd );
					trim();
				}
			}
			
			dispatchEvent( new Event("change") );
		}
		
		[Bindable("change")]
		public function canUndo():Boolean
		{
			if( this.undos.length == 0 ) return false;
			
			var cmd:ICommand = this.undos.peek();
			return( cmd && cmd.canUndo() );
		}
		
		public function redo( event:Event=null ):void
		{
			if( this.redos.length == 0 ) return;
			
			var cmd:ICommand = this.redos.pop();
			if( cmd && cmd.canRedo() )
			{
				cmd.redo( event );
				
				if( cmd.canUndo() )
				{
					this.undos.push( cmd );
					trim();
				}
			}
			
			dispatchEvent( new Event("change") );
		}
		
		[Bindable("change")]
		public function canRedo():Boolean
		{
			if( this.redos.empty ) return false;
			
			var cmd:ICommand = this.redos.peek();
			return( cmd && cmd.canUndo() );
		}
		
		public function clear():void
		{
			this.undos = new Array(); //.removeAll();
			this.redos = new Array(); //.removeAll();
		}
		
		public function trim():void
		{
			this.undos = this.undos.slice( 0, this.maxSize-1 );
		}

	}
}